import { extend } from 'umi-request';
import { isEmpty } from 'lodash';
import Cookies from 'js-cookie';
import router from '@/router';
import { RequestCanceler } from './httpCancel';
import { IRequestOptions } from './types/types';
import requestLoading from './request-loading';
import { defaultReqParams, authorityFailureCodes, responeStatus, deleteEmptyParams } from './constants';

const requestCanceler = new RequestCanceler();
const { startLoading, closeLoading, toastWithCallBack } = requestLoading;

export interface IRequestOptionsExt extends IRequestOptions {
  url: string;
  method: string;
  data?: object;
  customParams?: object;
}

/**
 * request原始对象
 */
const request = extend({
  prefix: import.meta.env.VITE_API_HOST as string,
  timeout: 60000,
  requestType: 'json',
});

// 全局请求拦截器
request.interceptors.request.use((url: string, tempOptions: IRequestOptions) => {
  // 组装请求配置
  const options = {
    ...defaultReqParams,
    ...tempOptions,
  };
  if (Cookies.get('token') && Cookies.get('sid')) {
    options.headers = {
      token: Cookies.get('token'),
      sid: Cookies.get('sid'),
    };
  }
  options.showLoading && startLoading();
  options.deleteEmptyParam && deleteEmptyParams(tempOptions.data || tempOptions.params);
  !options!.ignoreCancel && requestCanceler.addPending(tempOptions);
  return { url, options };
});

// 全局响应拦截器，克隆响应对象做解析处理
request.interceptors.response.use(async (originResponse, options: IRequestOptions) => {
  const response = await originResponse.clone().json();

  options.showLoading && (await closeLoading());

  response && requestCanceler.removePending(options);

  const { content, errorCode, errorMsg, status } = response;
  // 需要重新登录的错误码
  if (authorityFailureCodes.includes(errorCode)) {
    Cookies.remove('token');
    Cookies.remove('sid');
    router.replace({ path: '/login' });
  }
  if (status === responeStatus.SUCCESS) {
    return Promise.resolve(content);
  }

  toastWithCallBack(
    { message: !isEmpty(errorMsg) ? errorMsg : `服务器响应异常 ${status}` },
    () => {},
    !options!.ignoreErrorToast
  );
  return Promise.reject(response);
});

const http = (options: IRequestOptionsExt) => {
  const { url, data, method, customOptions = {} } = options;
  return request(url, {
    method,
    [method === 'get' ? 'params' : 'data']: data,
    ...customOptions,
  });
};

export function get(url: string, data?: object, customOptions?: IRequestOptions) {
  return http({
    url,
    data,
    method: 'get',
    customOptions,
  });
}

export function post(url: string, data?: object, customOptions?: IRequestOptions) {
  return http({
    url,
    method: 'post',
    data,
    customOptions,
  });
}
